﻿//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2025 Ryo Suzuki
//	Copyright (c) 2016-2025 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once
# include <array>
# include <ThirdParty/SFMT/SFMT.hpp>
# include "Common.hpp"
# include "Number.hpp"

namespace s3d
{
	namespace PRNG
	{
		// SFMT 19937 / Pseudo random number generator
		// Result: 64-bit value
		// Period: 2^19937-1
		// Footprint: 2,512 bytes
		class SFMT19937_64
		{
		public:

			using State_t = detail::SFMT_T;

			static constexpr size_t SeedSequencCount = 16;

			/// @brief 生成される整数値の型 | The integral type generated by the engine
			using result_type = uint64;

			/// @brief 乱数エンジンを作成し、内部状態を非決定的な乱数で初期化します。 | Constructs the engine and initializes the state with non-deterministic random numbers
			SIV3D_NODISCARD_CXX20
			SFMT19937_64();

			/// @brief 乱数エンジンを作成し、内部状態を初期化します。 | Constructs the engine and initializes the state.
			/// @param seed 内部状態の初期化に使われるシード値 | seed value to use in the initialization of the internal state
			SIV3D_NODISCARD_CXX20
			explicit SFMT19937_64(uint64 seed) noexcept;

			SIV3D_NODISCARD_CXX20
			explicit SFMT19937_64(const std::array<uint64, SeedSequencCount>& seeds) noexcept;

			void seed(uint64 seed) noexcept;

			void seed(const std::array<uint64, SeedSequencCount>& seeds) noexcept;

			/// @brief 生成される乱数の最小値を返します。 | Returns the minimum value potentially generated by the random-number engine
			/// @return 生成される乱数の最小値 | The minimum potentially generated value
			[[nodiscard]]
			static constexpr result_type min() noexcept;

			/// @brief 生成される乱数の最大値を返します。 | Returns the maximum value potentially generated by the random-number engine.
			/// @return 生成される乱数の最大値 | The maximum potentially generated value
			[[nodiscard]]
			static constexpr result_type max() noexcept;

			/// @brief 乱数を生成します。 | Generates a pseudo-random value.
			/// @return 生成された乱数 | A generated pseudo-random value
			result_type operator ()() noexcept;

			/// @brief [0, 1) の範囲の乱数を生成します。 | Generates a pseudo-random value in [0, 1)
			/// @return 生成された乱数 | A generated pseudo-random value
			[[nodiscard]]
			double generateReal() noexcept;

			[[nodiscard]]
			constexpr const State_t& serialize() const noexcept;

			constexpr void deserialize(const State_t& data) noexcept;

		private:

			State_t m_state;
		};
	}
}

# include "detail/SFMT.ipp"
